/*
 * CC3Layer.m
 *
 * cocos3d 0.6.1
 * Author: Bill Hollings
 * Copyright (c) 2010-2011 The Brenwill Workshop Ltd. All rights reserved.
 * http://www.brenwill.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * http://en.wikipedia.org/wiki/MIT_License
 * 
 * See header file CC3Layer.h for full API documentation.
 */

#include "CC3Layer.h"
#include "CC3OpenGLES11Foundation.h"

CC3Layer::CC3Layer() :
	cc3World(NULL)
{
	initInitialState();
}

CC3Layer::~CC3Layer()
{
	cc3World->release();
}

void CC3Layer::initializeControls()
{
	initializeContols();
}

void CC3Layer::initializeContols()
{
}

void CC3Layer::initInitialState()
{
	//ControllableCCLayer::initInitialState();
	shouldAlwaysUpdateViewport = false;
	initializeControls();
}

CC3World* CC3Layer::getCc3World()
{
	return cc3World;
}

void CC3Layer::setCc3World(CC3World* newValue)
{
	if (cc3World) 
	{
		cc3World->setIsRunning(false);				// Stop actions in old world.
		cc3World->setCc3Layer(NULL);				// Detach this layer from old world.
		cc3World->release(); //autorelease];					// Release old after new is retained, in case it's same object.
	}
	
	cc3World = newValue; cc3World->retain();				// Retain the new world.
	cc3World->setCc3Layer(this);				// Point the world back here
	updateViewport();					// Set the camera viewport
	cc3World->setIsRunning(getIsRunning());	// Start actions in new world.
	cc3World->updateWorld();					// Update the new world to ensure transforms have been calculated.
}

void CC3Layer::updateViewport()
{
	cc3World->getViewportManager()->updateBounds(boundingBoxInPixels(), cocos2d::CCDirector::sharedDirector()->getDeviceOrientation());
}

bool CC3Layer::getShouldAlwaysUpdateViewport()
{
	return shouldAlwaysUpdateViewport;
}

void CC3Layer::setShouldAlwaysUpdateViewport(bool newValue)
{
	shouldAlwaysUpdateViewport = newValue;
}

void CC3Layer::update(cocos2d::ccTime dt)
{
	cc3World->updateWorld(dt);
}

void CC3Layer::drawBackdrop()
{
	//LogTrace(@"%@ drawing backdrop", self);
	ControllableCCLayer::draw();
}

void CC3Layer::drawWorld()
{
	if (shouldAlwaysUpdateViewport) 
	{
		updateViewport();
	}
	
	cc3World->drawWorld();
}

int CC3Layer::touchPriority()
{
	return 0;
}

bool CC3Layer::handleTouch(cocos2d::CCTouch* touch, int touchType)
{
	cocos2d::CCSize cs = getContentSize();
	cocos2d::CCRect nodeBounds = cocos2d::CCRectMake(0, 0, cs.width, cs.height);
	cocos2d::CCPoint nodeTouchPoint = convertTouchToNodeSpace(touch);
	if(cocos2d::CCRect::CCRectContainsPoint(nodeBounds, nodeTouchPoint)) 
	{
		// todo
		//[cc3World touchEvent: touchType at: nodeTouchPoint];
		cc3World->touchEvent(touchType, nodeTouchPoint);
		
		return true;
	}
	
	return false;
}

void CC3Layer::draw()
{
	drawBackdrop();
	drawWorld();
}

void CC3Layer::onEnter()
{
	ControllableCCLayer::onEnter();
	updateViewport();
	cc3World->play();
}

void CC3Layer::onExit()
{
	ControllableCCLayer::onExit();
	cc3World->pause();
}

void CC3Layer::didUpdateHomeContentSizeFrom(cocos2d::CCSize oldHomeSize)
{
	ControllableCCLayer::didUpdateHomeContentSizeFrom(oldHomeSize);
	updateViewport();
}

void CC3Layer::deviceOrientationDidChange(cocos2d::ccDeviceOrientation newOrientation)
{
	ControllableCCLayer::deviceOrientationDidChange(newOrientation);
	updateViewport();
}

void CC3Layer::registerWithTouchDispatcher()
{
	cocos2d::CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this, touchPriority(), true);
}

bool CC3Layer::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
{
	return handleTouch(pTouch, cocos2d::CCTOUCHBEGAN);
}

//void CC3Layer::ccTouchMoved(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
//{
//	handleTouch(pTouch, CCTOUCHBEGAN);
//}

void CC3Layer::ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
{
	handleTouch(pTouch, cocos2d::CCTOUCHENDED);
}

void CC3Layer::ccTouchCancelled(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
{
	handleTouch(pTouch, cocos2d::CCTOUCHCANCELLED);
}
	
//@interface CC3Layer (TemplateMethods)
//-(void) updateViewport;
//-(void) drawWorld;
//-(int) touchPriority;
//-(BOOL) handleTouch: (UITouch*) touch ofType: (uint) touchType;
//@end
//
//@implementation CC3Layer
//
//@synthesize cc3World, shouldAlwaysUpdateViewport;
//
//- (void)dealloc {
//	[cc3World release];
//    [super dealloc];
//}
//
///**
// * Overridden to link the world back here as well, update the viewport of the new world,
// * and to start and stop actions. */
//-(void) setCc3World: (CC3World*) aWorld {
//	cc3World.isRunning = NO;				// Stop actions in old world.
//	cc3World.cc3Layer = nil;				// Detach this layer from old world.
//	[cc3World autorelease];					// Release old after new is retained, in case it's same object.
//
//	cc3World = [aWorld retain];				// Retain the new world.
//	cc3World.cc3Layer = self;				// Point the world back here
//	[self updateViewport];					// Set the camera viewport
//	cc3World.isRunning = self.isRunning;	// Start actions in new world.
//	[cc3World updateWorld];					// Update the new world to ensure transforms have been calculated.
//}
//
//-(NSString*) description {
//	return [NSString stringWithFormat: @"%@", [self class]];
//}
//
//
//#pragma mark Allocation and initialization
//
///** Overridden to invoke the initializeControls template method. */
//-(void) initInitialState {
//	[super initInitialState];
//	shouldAlwaysUpdateViewport = NO;
//	[self initializeControls];
//}
//
//// Spelling mistake on initial API...left in for backwards compatibility
//-(void) initializeContols {}
//
///**
// * For backwards compatibility, default invokes misspelled API method, which in turn does nothing.
// * Subclasses will override, and do not need to invoke this superclass implementation.
// */
//-(void) initializeControls {
//	[self initializeContols];
//}
//
//
//#pragma mark Updating layer
//
//-(void) update: (ccTime)dt {
//	[cc3World updateWorld: dt];
//}
//
//
//#pragma mark Drawing
//
///**
// * CCNode template method to draw this layer. Overridden to draw the colored backdrop and
// * then delegates 3D drawing to the contained CC3World instance.
// *
// * This method is invoked asynchronously to the update: loop, to keep the OpenGL ES drawing
// * separate from the processing from model updates.
// */
//-(void) draw {
//	[self drawBackdrop];
//	[self drawWorld];
//}
//
///** Delegates to the superclass to draw a colored backdrop if it has been established */
//-(void) drawBackdrop {
//	LogTrace(@"%@ drawing backdrop", self);
//	[super draw];
//}
//
///**
// * Draws the 3D world by delegating to the visit method of the contained CC3World instance.
// * If the shouldAlwaysUpdateViewport property is set to YES, then the viewport is updated first.
// */
//-(void) drawWorld {
//	if (shouldAlwaysUpdateViewport) {
//		[self updateViewport];
//	}
//	[cc3World drawWorld];
//}
//
//
//#pragma mark ControllableCCLayer support
//
///**
// * Invoked from cocos2d when this layer is first displayed.
// * Updates the device orientation in the 3D world, and starts it running.
// */
//-(void) onEnter {
//	[super onEnter];
//	[self updateViewport];
//	[cc3World play];
//}
//
///**
// * Invoked from cocos2d when this layer is removed.
// * Pauses the 3D world.
// */
//-(void) onExit {
//	[super onExit];
//	[cc3World pause];
//}
//
///**
// * Invoked automatically when the home content size has changed.
// * Updates the viewport to match the new layer dimensions.
// */
//-(void) didUpdateHomeContentSizeFrom: (CGSize) oldHomeSize {
//	[super didUpdateHomeContentSizeFrom: oldHomeSize];
//	[self updateViewport];
//}
//
///**
// * Invoked from the CCNodeController when the device orientation has changed.
// * Updates the 3D world to match the new device orientation and viewport dimensions, so
// * that 3D world will align itself with the new device orientation and layer dimensions.
// */
//-(void) deviceOrientationDidChange: (ccDeviceOrientation) newOrientation {
//	[super deviceOrientationDidChange: newOrientation];
//	[self updateViewport];
//}
//
///**
// * Updates the viewport of the contained CC3World instance with the dimensions of this layer
// * and the device orientation.
// *
// * Invoked automatically when the home content size (which is the content size, independent of
// * device orientation) changes, or when the device orientation changes.
// */
//-(void) updateViewport {
//	[cc3World.viewportManager updateBounds: self.boundingBoxInPixels
//					 withDeviceOrientation: [[CCDirector sharedDirector] deviceOrientation]];
//}
//
//
//#pragma mark Touch handling
//
//// Handle touch events one at a time.
//-(void) registerWithTouchDispatcher {
//	[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate: self
//													 priority: self.touchPriority
//											  swallowsTouches:YES];
//}
//
///**
// * The priority at which touch events are delegated to this layer.
// * Default is zero. Subclasses may override.
// */
//-(int) touchPriority {
//	return 0;
//}
//
//// Handles the initial finger-down touch events.
//-(BOOL) ccTouchBegan: (UITouch *)touch withEvent: (UIEvent *)event {
//	return [self handleTouch: touch ofType: kCCTouchBegan];
//}
//
//// Handles the final finger-up touch events.
//-(void) ccTouchEnded: (UITouch *)touch withEvent: (UIEvent *)event {
//	[self handleTouch: touch ofType: kCCTouchEnded];
//}
//
//// Handles cancelled touch events.
//-(void) ccTouchCancelled: (UITouch *)touch withEvent: (UIEvent *)event {
//	[self handleTouch: touch ofType: kCCTouchCancelled];
//}
//
///*
//// The ccTouchMoved:withEvent: method is optional for the <CCTouchDelegateProtocol>.
//// The event dispatcher will not dispatch events for which there is no method
//// implementation. Since the touch-move events are both voluminous and seldom used,
//// the implementation of ccTouchMoved:withEvent: has been left out of the default
//// CC3Layer implementation. To receive and handle touch-move events for object
//// picking, copy the following method implementation to your CC3Layer subclass.
//
//// Handles intermediate finger-moved touch events.
//-(void) ccTouchMoved: (UITouch *)touch withEvent: (UIEvent *)event {
//	[self handleTouch: touch ofType: kCCTouchMoved];
//}
//*/
//
///**
// * Invoked when any of the touch event handler methods are invoked. Checks that
// * the touch event is within the bounds of this layer and forwards the event to
// * the CC3World instance. Returns whether the event was handled and forwarded.
// */
//-(BOOL) handleTouch: (UITouch*) touch ofType: (uint) touchType {
//	CGSize cs = self.contentSize;
//	CGRect nodeBounds = CGRectMake(0, 0, cs.width, cs.height);
//	CGPoint nodeTouchPoint = [self convertTouchToNodeSpace: touch];
//	if(CGRectContainsPoint(nodeBounds, nodeTouchPoint)) {
//		[cc3World touchEvent: touchType at: nodeTouchPoint];
//		return YES;
//	}
//	return NO;
//}
//
//@end


